cmake_minimum_required(VERSION 3.5.1)

set (CMAKE_CXX_STANDARD 17)

if(MSVC)
  add_definitions(-D_WIN32_WINNT=0x600)
endif()

find_package(Threads REQUIRED)

if(GRPC_AS_SUBMODULE)
  add_subdirectory(../../.. ${CMAKE_CURRENT_BINARY_DIR}/grpc EXCLUDE_FROM_ALL)
  message(STATUS "Using gRPC via add_subdirectory.")

  set(_PROTOBUF_LIBPROTOBUF libprotobuf)
  set(_REFLECTION grpc++_reflection)
  if(CMAKE_CROSSCOMPILING)
    find_program(_PROTOBUF_PROTOC protoc)
  else()
    set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)
  endif()
  set(_GRPC_GRPCPP grpc++)
  if(CMAKE_CROSSCOMPILING)
    find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin)
  else()
    set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:grpc_cpp_plugin>)
  endif()
elseif(GRPC_FETCHCONTENT)
  message(STATUS "Using gRPC via add_subdirectory (FetchContent).")
  include(FetchContent)
  FetchContent_Declare(
    grpc
    GIT_REPOSITORY https://github.com/grpc/grpc.git
    GIT_TAG        vGRPC_TAG_VERSION_OF_YOUR_CHOICE)
  FetchContent_MakeAvailable(grpc)

  set(_PROTOBUF_LIBPROTOBUF libprotobuf)
  set(_REFLECTION grpc++_reflection)
  set(_PROTOBUF_PROTOC $<TARGET_FILE:protoc>)
  set(_GRPC_GRPCPP grpc++)
  if(CMAKE_CROSSCOMPILING)
    find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin)
  else()
    set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:grpc_cpp_plugin>)
  endif()
else()
  set(protobuf_MODULE_COMPATIBLE TRUE)
  find_package(Protobuf REQUIRED)
  message(STATUS "Using protobuf ${Protobuf_VERSION}")

  set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf)
  set(_REFLECTION gRPC::grpc++_reflection)
  if(CMAKE_CROSSCOMPILING)
    find_program(_PROTOBUF_PROTOC protoc)
  else()
    set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)
  endif()

  find_package(gRPC CONFIG REQUIRED)
  message(STATUS "Using gRPC ${gRPC_VERSION}")

  set(_GRPC_GRPCPP gRPC::grpc++)
  if(CMAKE_CROSSCOMPILING)
    find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin)
  else()
    set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>)
  endif()
endif()


# ================== gRPC生成函数 ==================
function(grpc_generate_cpp SRC_FILES HDR_FILES)
  if(NOT ARGN)
    message(SEND_ERROR "Error: grpc_generate_cpp() called without any proto files")
    return()
  endif()

  set(${SRC_FILES})
  set(${HDR_FILES})

  foreach(proto_file ${ARGN})
    get_filename_component(proto_name ${proto_file} NAME_WE)
    get_filename_component(proto_full_path ${proto_file} ABSOLUTE)
    file(RELATIVE_PATH proto_relative_path ${CMAKE_CURRENT_SOURCE_DIR} ${proto_full_path})
    get_filename_component(relative_directory ${proto_relative_path} DIRECTORY)

    if(NOT relative_directory)
      set(proto_name_full "${proto_name}")
    else()
      set(proto_name_full "${relative_directory}/${proto_name}")
    endif()

    set(generated_pb_cc "${CMAKE_CURRENT_BINARY_DIR}/${proto_name_full}.pb.cc")
    set(generated_pb_h "${CMAKE_CURRENT_BINARY_DIR}/${proto_name_full}.pb.h")
    set(generated_grpc_pb_cc "${CMAKE_CURRENT_BINARY_DIR}/${proto_name_full}.grpc.pb.cc")
    set(generated_grpc_pb_h "${CMAKE_CURRENT_BINARY_DIR}/${proto_name_full}.grpc.pb.h")

    list(APPEND ${SRC_FILES} "${generated_pb_cc}")
    list(APPEND ${HDR_FILES} "${generated_pb_h}")
    list(APPEND ${SRC_FILES} "${generated_grpc_pb_cc}")
    list(APPEND ${HDR_FILES} "${generated_grpc_pb_h}")

    add_custom_command(
      OUTPUT "${generated_pb_cc}" "${generated_pb_h}" 
             "${generated_grpc_pb_cc}" "${generated_grpc_pb_h}"
      COMMAND ${_PROTOBUF_PROTOC}
      ARGS --grpc_out=${CMAKE_CURRENT_BINARY_DIR}
           --cpp_out=${CMAKE_CURRENT_BINARY_DIR}
           --plugin=protoc-gen-grpc=${_GRPC_CPP_PLUGIN_EXECUTABLE}
           -I ${CMAKE_CURRENT_SOURCE_DIR}
           ${proto_relative_path}
      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
      DEPENDS ${proto_file}
      COMMENT "Generating gRPC sources for ${proto_file}"
    )
  endforeach()

  set_source_files_properties(${${SRC_FILES}} ${${HDR_FILES}} PROPERTIES GENERATED TRUE)
  set(${SRC_FILES} ${${SRC_FILES}} PARENT_SCOPE)
  set(${HDR_FILES} ${${HDR_FILES}} PARENT_SCOPE)
endfunction()

# ================== 生成具体的proto文件 ==================
grpc_generate_cpp(TASK_FLOW_SRC TASK_FLOW_HDR 
    ${CMAKE_CURRENT_SOURCE_DIR}/grpc/proto/task_flow.proto
)

# ================== 创建gRPC库 ==================
add_library(hmi_grpc_proto STATIC
    ${TASK_FLOW_SRC}
)

target_include_directories(hmi_grpc_proto PUBLIC
    ${CMAKE_CURRENT_BINARY_DIR}  # 生成的pb.h文件位置
)

target_link_libraries(hmi_grpc_proto
    ${_REFLECTION}
    ${_GRPC_GRPCPP}
    ${_PROTOBUF_LIBPROTOBUF}
)